package cn.wizzer.app.web.commons.doc;

import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Collection;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * 利用POI进行Word文件相关的操作，针对docx形式的封装
 *
 * @author
 *
 * <p>Modification History:</p>
 * <p>Date       Author      Description</p>
 * <p>------------------------------------------------------------------</p>
 * <p> </p>
 * <p>  </p>
 */
public class BookMarks {

    /** 保存Word文件中定义的标签  **/
    private HashMap<String, BookMark> _bookmarks = null;

    /**
     * 构造函数，用以分析文档，解析出所有的标签
     *
     * @param document  Word OOXML document instance.
     */
    public BookMarks(XWPFDocument document) {

        //初始化标签缓存
        this._bookmarks = new HashMap<String, BookMark>();

        //****************处理正文中的标签

        // 首先解析文档普通段落中的标签
        this.procParaList(document.getParagraphs());
        //this.procParaList2(document);

        //利用繁琐的方法，从所有的表格中得到得到标签，处理比较原始和简单
        List<XWPFTable> tableList = document.getTables();
        for (XWPFTable table : tableList) {
            //得到表格的列信息
            List<XWPFTableRow> rowList = table.getRows();
            for (XWPFTableRow row : rowList){
                //得到行中的列信息
                List<XWPFTableCell> cellList = row.getTableCells();
                for (XWPFTableCell cell : cellList) {
                    //逐个解析标签信息
                    //this.procParaList(cell.getParagraphs(), row);
                    this.procParaList(cell);
                }
            }
        }

        //****************处理页眉中的标签
        List<XWPFHeader> headlist = document.getHeaderList();
        for (XWPFHeader head : headlist) {
            // 首先解析文档普通段落中的标签
            this.procParaListHeader(head.getParagraphs());
            //利用繁琐的方法，从所有的表格中得到得到标签，处理比较原始和简单
            List<XWPFTable> tableListHeader = head.getTables();
            for (XWPFTable tableHeader : tableListHeader) {
                //得到表格的列信息
                List<XWPFTableRow> rowListHeader = tableHeader.getRows();
                for (XWPFTableRow rowHeader : rowListHeader){
                    //得到行中的列信息
                    List<XWPFTableCell> cellListHeader = rowHeader.getTableCells();
                    for (XWPFTableCell cellHeader : cellListHeader) {
                        //逐个解析标签信息
                        //this.procParaList(cell.getParagraphs(), row);
                        this.procParaList(cellHeader);
                    }
                }
            }
        }

    }


    /**
     * 根据标签名称，获得标签的相关定义，如果不存在，则返回空
     * @param bookmarkName   标签名称
     * @return    返回封装好的对象
     */
    public BookMark getBookmark(String bookmarkName) {
        BookMark bookmark = null;
        if(this._bookmarks.containsKey(bookmarkName)) {
            bookmark = this._bookmarks.get(bookmarkName);
        }
        return   bookmark;
    }

    /**
     * 得到所有的标签信息集合
     *
     * @return 缓存的标签信息集合
     */
    public Collection<BookMark> getBookmarkList() {
        return(this._bookmarks.values());
    }

    /**
     * 返回文档中的标签名称迭代器
     * @return  由Map KEY 转换的迭代器
     */
    public Iterator<String> getNameIterator() {
        return(this._bookmarks.keySet().iterator());
    }


    private void procParaList(XWPFTableCell cell){
        List<XWPFParagraph> paragraphList = cell.getParagraphs();

        for(XWPFParagraph paragraph : paragraphList){
            //得到段落中的标签标记
            List<CTBookmark> bookmarkList = paragraph.getCTP().getBookmarkStartList();
            for (CTBookmark bookmark : bookmarkList ) {
                this._bookmarks.put(bookmark.getName(),
                        new BookMark(bookmark, paragraph, cell));
            }
        }
    }
    /**
     * 解析表格中的标签
     * @param paragraphList   传入的段落列表
     * @param tableRow   对应的表格行对象
     */
    @SuppressWarnings("unused")
    private void procParaList(List<XWPFParagraph> paragraphList, XWPFTableRow tableRow) {

        NamedNodeMap attributes = null;
        Node colFirstNode = null;
        Node colLastNode = null;
        int firstColIndex = 0;
        int lastColIndex = 0;

        //循环判断，解析段落中的标签
        for (XWPFParagraph paragraph : paragraphList) {
            //得到段落中的标签标记
            List<CTBookmark> bookmarkList = paragraph.getCTP().getBookmarkStartList();

            for (CTBookmark bookmark : bookmarkList ) {
                // With a bookmark in hand, test to see if the bookmarkStart tag
                // has w:colFirst or w:colLast attributes. If it does, we are
                // dealing with a bookmarked table cell. This will need to be
                // handled differnetly - I think by an different concrete class
                // that implements the Bookmark interface!!
                attributes = bookmark.getDomNode().getAttributes();
                if(attributes != null) {

                    // Get the colFirst and colLast attributes. If both - for
                    // now - are found, then we are dealing with a bookmarked
                    // cell.
                    colFirstNode = attributes.getNamedItem("w:colFirst");
                    colLastNode = attributes.getNamedItem("w:colLast");
                    if(colFirstNode != null && colLastNode != null) {

                        // Get the index of the cell (or cells later) from them.
                        // First convefrt the String values both return to primitive
                        // int value. TO DO, what happens if there is a
                        // NumberFormatException.
                        firstColIndex = Integer.parseInt(colFirstNode.getNodeValue());
                        lastColIndex = Integer.parseInt(colLastNode.getNodeValue());
                        // if the indices are equal, then we are dealing with a#
                        // cell and can create the bookmark for it.
                        if(firstColIndex == lastColIndex) {
                            this._bookmarks.put(bookmark.getName(),
                                    new BookMark(bookmark, paragraph,
                                            tableRow.getCell(firstColIndex)));
                        }
                        else {
                            System.out.println("This bookmark " + bookmark.getName() +
                                    " identifies a number of cells in the "
                                    + "table. That condition is not handled yet.");
                        }
                    }
                    else {
                        this._bookmarks.put(bookmark.getName(),
                                new BookMark(bookmark, paragraph,tableRow.getCell(1)));
                    }
                }
                else {
                    this._bookmarks.put(bookmark.getName(),
                            new BookMark(bookmark, paragraph,tableRow.getCell(1)));
                }
            }
        }
    }

    /**
     * 解析普通段落中的标签
     * @param paragraphList  传入的段落
     */
    private void procParaList(List<XWPFParagraph> paragraphList) {
        for (XWPFParagraph paragraph : paragraphList) {
            List<CTBookmark>  bookmarkList = paragraph.getCTP().getBookmarkStartList();
            //循环加入标签
            for (CTBookmark bookmark : bookmarkList) {
                this._bookmarks.put(bookmark.getName(),
                        new BookMark(bookmark, paragraph));
            }
        }
    }

    /**
     * 解析普通段落中的标签
     * @param paragraphList  传入的段落
     */
    private void procParaListHeader(List<XWPFParagraph> paragraphList) {
        for (XWPFParagraph paragraph : paragraphList) {
            List<CTBookmark>  bookmarkList = paragraph.getCTP().getBookmarkStartList();
            //循环加入标签
            for (CTBookmark bookmark : bookmarkList) {
                this._bookmarks.put(bookmark.getName(),
                        new BookMark(bookmark, paragraph));
            }
        }
    }
    /**
     * 解析普通段落中的标签
     * @param
     */
    private void procParaList2(XWPFDocument doc) {
        for (XWPFParagraph paragraph : doc.getParagraphs()) {
            for(XmlObject object:paragraph.getCTP().getRList()){
                if(object.getDomNode().getNodeName().equals("w:bookmarkStart")){
                    //System.out.println("----------" + object.getDomNode().getNodeValue());
                }else{
                    getNode(object.getDomNode());
                }
                NodeList nodelist = object.getDomNode().getChildNodes();
                //NamedNodeMap list = node.getAttributes();
               /* System.out.println(nodelist.getLength());*/
                //Node a = node.getLastChild();

                /*for(int i = 0 ;i<nodelist.getLength();i++){
                    Node node = nodelist.item(i);
                    if (node.getNodeName().equals("w:bookmarkStart")){
                        System.out.println("----------" + node.getNodeValue());
                    }
                }*/
               /* System.out.println();*/
            }
        }
    }
    private void getNode(Node node){
        NodeList nodelist = node.getChildNodes();
        //System.out.println(nodelist.getLength()+"--=-=");
        if(nodelist.getLength()>0){
            for (int i= 0 ;i<nodelist.getLength();i++){
                Node childNode = nodelist.item(i);
                //System.out.println("----------" + childNode.getNodeName());
                if(childNode.getNodeName().equals("w:bookmarkStart")){
                    String name = ((Element)childNode).getAttribute("w:name");
                    //CTBookmark bookmark = (CTBookmark)childNode;
                    //System.out.println("............" + bookmark.getName());
                }else{
                    getNode(childNode);
                }
            }
        }
        System.out.println("--------------------------------------------------" );
    }
}
